// Copyright (c) 2016, Open DICOMweb Project. All rights reserved.
// Use of this source code is governed by the open source license
// that can be found in the LICENSE file.
// Original author: Jim Philbin <jfphilbin@gmail.edu> -
// See the AUTHORS file for other contributors.

import 'package:dicom_core/src/issues.dart';
import 'package:dicom_core/src/string/hexadecimal.dart';
import 'package:dicom_core/src/tag/tag.dart';
import 'package:dicom_core/src/vr/vr.dart';

class InvalidTagError extends Error {
  Object tag;

  InvalidTagError(this.tag);

  @override
  String toString() => Tag.toMsg(tag);

  static String _msg<K>(Object tag) => 'InvalidTagError: $tag';
}

//Urgent: jim figure out best way to handel invalid tags
invalidTagError(Object obj, [Issues? issues]) {
  final msg = 'InvalidTagError: $obj';
  if (issues != null) issues.add(msg);
  return obj;
}

class InvalidTagTypeError extends Error {
  String msg;
  Tag tag;

  InvalidTagTypeError(this.tag, this.msg);

  @override
  String toString() => 'InvalidTagTypeError - $msg: $tag';
}

nonIntegerTag(int index, [Issues? issues]) =>
    _doTagError(index, issues, 'Non-Integer Tag');

nonFloatTag(int index, [Issues? issues]) =>
    _doTagError(index, issues, 'Non-Float Tag');

nonStringTag(int index, [Issues? issues]) =>
    _doTagError(index, issues, 'Non-String Tag');

nonSequenceTag(int index, [Issues? issues]) =>
    _doTagError(index, issues, 'Non-Sequence Tag');

nonUidTag(int index, [Issues? issues]) =>
    _doTagError(index, issues, 'Non-Uid Tag');

_doTagError(int index, Issues? issues, [String msg = 'Invalid Tag Type']) {
  final tag = Tag.lookup(index);
  final s = '$msg: $tag';
  if (issues != null) issues.add(s);
  return null;
}

//TODO: convert this to handle both int and String and remove next two Errors
class InvalidTagKeyError<K> extends Error {
  K key;
  int? vrIndex;
  String? creator;

  InvalidTagKeyError(this.key, [this.vrIndex, this.creator]);

  @override
  String toString() => _msg(key, vrIndex, creator);

  static String _msg<K>(K key, [int? vrIndex, String? creator]) =>
      'InvalidTagKeyError: "$_value" $vrIndex creator:"$creator"';

  static String _value(Object key) {
    if (key == null) return 'null';
    if (key is String) return key;
    if (key is int) return Tag.toDcm(key);
    return key.toString();
  }
}

invalidTagKey<K>(K key, [int? vrIndex, String? creator]) {
  return null;
}

//Flush when replaced with InvalidTagKeyError
class InvalidTagCodeError extends Error {
  int code;
  String? msg;

  InvalidTagCodeError(this.code, [this.msg]);

  @override
  String toString() => _msg(code, msg);

  static String _msg(int code, String? msg) =>
      'InvalidTagCodeError: "${_value(code)}": $msg';

  static String _value(int code) => (code == null) ? 'null' : Tag.toDcm(code);
}

invalidTagCode(int code, [String? msg]) {
  return null;
}

//Flush when replaced with InvalidTagKeyError
class InvalidTagKeywordError extends Error {
  String keyword;

  InvalidTagKeywordError(this.keyword);

  @override
  String toString() => _msg(keyword);

  static String _msg(String keyword) => 'InvalidTagKeywordError: "$keyword"';
}

tagKeywordError(String keyword) {
  return null;
}

//TODO: convert this to handle both int and String and remove next two Errors
class InvalidVRForTagError extends Error {
  Tag tag;
  int vrIndex;

  InvalidVRForTagError(this.tag, this.vrIndex);

  @override
  String toString() => _msg(tag, vrIndex);

  static String _msg(Tag tag, int vrIndex) {
    final vr = vrIdFromIndex(vrIndex);
    return 'Error: Invalid VR (Value Representation) "$vr" for $tag';
  }
}

 invalidVRForTag(Tag tag, int vrIndex) {
  return null;
}

 invalidVRIndexForTag(Tag tag, int vrIndex) {
//	final vr = VR.lookupByIndex(vrIndex);
  return null;
}

 invalidVRCodeForTag(Tag tag, int vrCode) {
  return null;
}

/*
class InvalidVFLengthError extends Error {
  final int length;
  final int maxVFLenght;

  InvalidVFLengthError(this.length, this.maxVFLenght) {
    if (log != null) log.error(toString());
  }

  @override
  String toString() => _msg(length, maxVFLenght);

  static String _msg(int length, int maxVFLength) =>
      'InvalidVFLengthError: lengthInBytes(${length}'
      'maxVFLength($maxVFLength)';
}

Null invalidVFLength(int length, int maxVFLength) {
  log.error(InvalidVFLengthError._msg(length, maxVFLength));
  if (throwOnError) throw  InvalidVFLengthError(length, maxVFLength);
  return null;
}
*/

class InvalidValuesTypeError<V> extends Error {
  final Tag tag;
  final Iterable<V> values;

  InvalidValuesTypeError(this.tag, this.values) {
  }

  @override
  String toString() => _msg(tag, values);

  static String _msg<V>(Tag tag, Iterable<V> values) =>
      'InvalidValuesTypeError:\n  Tag(${tag.info})\n  values: $values';
}

 invalidValuesTypeError<V>(Tag tag, Iterable<V> values) {
  return null;
}

class InvalidValuesLengthError<V> extends Error {
  final Tag tag;
  final Iterable<V> values;

  InvalidValuesLengthError(this.tag, this.values) {
  }

  @override
  String toString() => _msg(tag, values);

  static String _msg<V>(Tag? tag, Iterable<V>? values) {
    if (tag == null || tag is! Tag) return invalidTagError(tag!);
    return 'InvalidValuesLengthError:\n  Tag(${tag.info})\n  values: $values';
  }
}

 invalidValuesLengthError<V>(Tag tag, Iterable<V>? values,
    [Issues? issues]) {
  final msg = InvalidValuesLengthError._msg(tag, values);
  if (issues != null) issues.add(msg);
  return null;
}

class InvalidTagValuesError<V> extends Error {
  final Tag tag;
  final Iterable<V> values;

  InvalidTagValuesError(this.tag, this.values);

  @override
  String toString() => '${_msg(tag, values)}';

  static String _msg<V>(Tag tag, Iterable<V> values) =>
      'InvalidValuesError: ${tag.info}\n  values: $values';
}

 invalidTagValuesError<V>(Tag tag, Iterable<V> values) {
  return null;
}

/// An invalid DICOM Group number [Error].
/// Note: Don't use this directly, use [invalidGroupError] instead.
class InvalidGroupError extends Error {
  int group;

  InvalidGroupError(this.group);

  @override
  String toString() => _msg(group);

  static String _msg(int group) => 'Invalid DICOM Group Error: ${hex16(group)}';
}

 invalidGroupError(int group) {
  return null;
}
